﻿using ChineseChess.Utils;
using ChineseChessFen;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ChineseChess.Models
{
    /// <summary>
    /// 棋局
    /// </summary>
    public class Chess
    {
        private char[,] board { set; get; }
        public List<Piece> Pieces { set; get; }
        public List<May> Mays { set; get; }
        public List<Select> Selects { set; get; }

        public Chess()
        {
            Init();
        }


        private const char 俥 = 'R';
        private const char 車 = 'r';
        private const char 傌 = 'N';
        private const char 馬 = 'n';
        private const char 相 = 'B';
        private const char 象 = 'b';
        private const char 仕 = 'A';
        private const char 士 = 'a';
        private const char 帥 = 'K';
        private const char 將 = 'k';
        private const char 炮 = 'C';
        private const char 砲 = 'c';
        private const char 兵 = 'P';
        private const char 卒 = 'p';
        /// <summary>
        /// 棋子名称
        /// </summary>
        private static readonly Dictionary<char, string> PieceName = new()
        {
            { 車, "車" },
            { 俥, "俥" },
            { 馬, "馬" },
            { 傌, "傌" },
            { 相, "相" },
            { 象, "象" },
            { 仕, "仕" },
            { 士, "士" },
            { 將, "將" },
            { 帥, "帥" },
            { 砲, "砲" },
            { 炮, "炮" },
            { 卒, "卒" },
            { 兵, "兵" }
        };
        /// <summary>
        /// 判断棋子颜色
        /// </summary>
        /// <param name="piece"></param>
        /// <returns></returns>
        private static PieceColor GetPieceColor(char piece)
        {
            if (piece >= 'a' && piece <= 'z')
            {
                return PieceColor.Black;
            }
            else if (piece >= 'A' && piece <= 'Z')
            {
                return PieceColor.Red;
            }
            else
            {
                return PieceColor.White;
            }
        }
        /// <summary>
        /// 棋子颜色
        /// </summary>
        private enum PieceColor
        {
            /// <summary>
            /// 空
            /// </summary>
            White,
            /// <summary>
            /// 红
            /// </summary>
            Red,
            /// <summary>
            /// 黑
            /// </summary>
            Black
        }

        /// <summary>
        /// 行棋记录
        /// 左到右a-j
        /// 下到上0-9
        /// </summary>
        private List<string> steps;

        /// <summary>
        /// 当前步数
        /// </summary>
        public int Count
        {
            get
            {
                return steps.Count;
            }
        }

        private void Init()
        {
            board = (char[,])ConstUtil.Board.Clone();
            Pieces = new();

            for (int i = 0; i < 10; i++)
            {
                for (int j = 0; j < 9; j++)
                {
                    if (board[i, j] != '0')
                    {
                        Piece piece = new();
                        piece.Name = PieceName[board[i, j]];
                        piece.X = i;
                        piece.Y = j;
                        piece.Color = GetPieceColor(board[i, j]) == PieceColor.Red ? "DarkRed" : "black";
                        Pieces.Add(piece);
                    }
                }
            }

            Mays = new();
            Selects = new();
            steps = new(1000);
        }

        /// <summary>
        /// 坐标变通用棋步
        /// </summary>
        /// <param name="x1"></param>
        /// <param name="y1"></param>
        /// <param name="x2"></param>
        /// <param name="y2"></param>
        /// <returns></returns>
        private string ToStep(int x1, int y1, int x2, int y2)
        {
            StringBuilder builder = new();
            builder.Append((char)('a' + y1));
            builder.Append(9 - x1);
            builder.Append((char)('a' + y2));
            builder.Append(9 - x2);
            return builder.ToString();
        }

        /// <summary>
        /// 通用棋步变坐标
        /// </summary>
        /// <param name="step"></param>
        /// <returns></returns>
        private int[] ToPoints(string step)
        {
            return new int[]
            {
                9-(step[1]-'0'),
                step[0]-'a',
                9-(step[3]-'0'),
                step[2]-'a'
            };
        }

        /// <summary>
        /// 行棋
        /// </summary>
        /// <param name="x1"></param>
        /// <param name="y1"></param>
        /// <param name="x2"></param>
        /// <param name="y2"></param>
        public void Move(int x1, int y1, int x2, int y2)
        {
            board[x2, y2] = board[x1, y1];
            board[x1, y1] = '0';
            Pieces = new();

            for (int i = 0; i < 10; i++)
            {
                for (int j = 0; j < 9; j++)
                {
                    if (board[i, j] != '0')
                    {
                        Piece piece = new();
                        piece.Name = PieceName[board[i, j]];
                        piece.X = i;
                        piece.Y = j;
                        piece.Color = GetPieceColor(board[i, j]) == PieceColor.Red ? "DarkRed" : "black";
                        Pieces.Add(piece);
                    }
                }
            }
            //记录棋步
            steps.Add(ToStep(x1, y1, x2, y2));
            Selects = new List<Select>()
            {
                new Select(){X=x1,Y=y1},
                new Select(){X=x2,Y=y2}
            };
        }

        /// <summary>
        /// 计算机走一步
        /// </summary>
        public void ComputerMove()
        {
            string fen;
            //红方
            if (Count % 2 == 0)
            {
                fen = FenUtil.BoardToFen(board) + " w ";

                Debug.WriteLine("红方电脑，步数："+Count+",fen="+fen);
            }
            //黑方
            else
            {
                fen = FenUtil.BoardToFen(board) + " b ";
                Debug.WriteLine("黑方电脑，步数：" + Count + ",fen=" + fen);
            }
            //默认思考10秒
            string output = EngineUtil.BestStep(fen, 10000);
            int start = output.IndexOf("bestmove");
            start = output.IndexOf(" ", start + "bestmove".Length);
            int end = output.IndexOf(" ", start + 2);
            if (end == -1)
            {
                end = output.IndexOf("\n", start+2);
            }
            try
            {
                string move = output.Substring(start, end - start + 1).Trim();
                Debug.WriteLine(move);
                int[] points = ToPoints(move);

                List<int[]> allsteps = AllMoves();
                int idx = 1;
                foreach(var item in allsteps)
                {
                    Debug.WriteLine(idx+"::"+string.Join(" ", item));
                    idx++;
                }

                Debug.WriteLine(points[0] + "," + points[1] + "-->>" + points[2] + "," + points[3]);
                Move(points[0], points[1], points[2], points[3]);

            }
            catch(Exception exception)
            {
                Debug.WriteLine(exception.Message);
            }
        }

        /// <summary>
        /// 当前行动方所有合法棋步
        /// </summary>
        /// <returns></returns>
        public List<int[]> AllMoves()
        {
            return ChineseChessPieceRule.PieceRule.GetPiecesMovesRight(board, Count % 2 == 0 ? "red" : "black");
        }
    }
}
